package nu.zoom.swing.desktop.frame;

import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.UUID;

import nu.zoom.swing.desktop.WorkbenchFrame;
import nu.zoom.swing.desktop.WorkbenchFrameListener;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public abstract class AbstractWorkbenchFrame implements WorkbenchFrame {

	private Log log = LogFactory.getLog(getClass());
	private final String guid;
	protected final ArrayList<WorkbenchFrameListener> frameListeners = new ArrayList<WorkbenchFrameListener>();

	public AbstractWorkbenchFrame() {
		super();
		guid = UUID.randomUUID().toString();
	}

	@Override
	public synchronized void addFrameListener(WorkbenchFrameListener listener) {
		if ((listener != null) && (!frameListeners.contains(listener))) {
			frameListeners.add(listener);
		}
	}

	@Override
	public synchronized void removeFrameListener(WorkbenchFrameListener listener) {
		if (listener != null) {
			frameListeners.remove(listener);
		}
	}

	protected synchronized void fireFrameClosed() {
		if (log.isTraceEnabled()) {
			log.trace("Informing " + frameListeners.size() + " listeners that frame is closed");
		}
		for (final WorkbenchFrameListener listener : frameListeners) {
			EventQueue.invokeLater(new Runnable() {

				@Override
				public void run() {
					listener.frameClosed(AbstractWorkbenchFrame.this);
				}
			});
		}
	}

	protected synchronized void fireFrameWillDispose() {
		if (log.isTraceEnabled()) {
			log.trace("Informing " + frameListeners.size() + " listeners that frame will dispose");
		}
		for (final WorkbenchFrameListener listener : frameListeners) {
			EventQueue.invokeLater(new Runnable() {

				@Override
				public void run() {
					listener.frameWillDispose(AbstractWorkbenchFrame.this);
				}
			});
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see nu.zoom.swing.desktop.WorkbenchFrame#dispose()
	 */
	@Override
	public void dispose() {
		fireFrameWillDispose();
		delegateDispose();
	}

	/**
	 * Subclasses should dispose of their Swing/AWT frame and when the frame has
	 * been disposed call {@link #fireFrameClosed()}
	 * 
	 */
	protected abstract void delegateDispose();

	@Override
	public boolean equals(Object obj) {
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		final AbstractWorkbenchFrame other = (AbstractWorkbenchFrame) obj;
		if ((this.guid == null) ? (other.guid != null) : !this.guid.equals(other.guid)) {
			return false;
		}
		return true;
	}

	@Override
	public int hashCode() {
		int hash = 3;
		hash = 97 * hash + (this.guid != null ? this.guid.hashCode() : 0);
		return hash;
	}
}
